package com.framework.base.taglib.ui; 

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;

/**
 * @Description:功能描述
 * @Company: framework
 * @version 1.0
 * @Date 2011-6-16 上午12:18:48
 */
@SuppressWarnings("serial")
public class JSTLPropertyTag extends BodyTagSupport{


    /*
     * (One almost wishes XML and JSP could support "anonymous tags,"
     * given the amount of trouble we had naming this one!)  :-)  - sb
     */

    //*********************************************************************
    // Internal state

    protected Object value;                     // tag attribute
    protected String def;			// tag attribute
    protected boolean escapeXml;		// tag attribute
    private boolean needBody;			// non-space body needed?
    protected int maxlength;
    private boolean displayTitle;
    //*********************************************************************
    // Construction and initialization

    public void setDisplayTitle(boolean displayTitle) {
		this.displayTitle = displayTitle;
	}

	/**
     * Constructs a new handler.  As with TagSupport, subclasses should
     * not provide other constructors and are expected to call the
     * superclass constructor.
     */
    public JSTLPropertyTag() {
        super();
        init();
    }

    // resets local state
    private void init() {
        value = def = null;
        escapeXml = true;
	needBody = false;
	maxlength=0;
	displayTitle=true;
    }

    // Releases any resources we may have (or inherit)
    public void release() {
        super.release();
        init();
    }


    //*********************************************************************
    // Tag logic

    // evaluates 'value' and determines if the body should be evaluted
    public int doStartTag() throws JspException {

      needBody = false;			// reset state related to 'default'
      super.bodyContent = null;  // clean-up body (just in case container is pooling tag handlers)

      try {
	// print value if available; otherwise, try 'default'
	if (value != null) {
            out(pageContext, escapeXml, getResultbyLimitLength(value.toString(), maxlength),value.toString(),displayTitle);
	    return SKIP_BODY;
	} else {
	    // if we don't have a 'default' attribute, just go to the body
	    if (def == null) {
		needBody = true;
		return EVAL_BODY_BUFFERED;
	    }

	    // if we do have 'default', print it
	    if (def != null) {
		// good 'default'
                out(pageContext, escapeXml, getResultbyLimitLength(def.toString(), maxlength),def.toString(),displayTitle);
	    }
	    return SKIP_BODY;
	}
      } catch (IOException ex) {
	throw new JspException(ex.getMessage(), ex);
      }
    }

    // prints the body if necessary; reports errors
    public int doEndTag() throws JspException {
      try {
	if (!needBody)
	    return EVAL_PAGE;		// nothing more to do

	// trim and print out the body
	if (bodyContent != null && bodyContent.getString() != null)
            out(pageContext, escapeXml, getResultbyLimitLength(bodyContent.getString().trim(), maxlength),bodyContent.getString().trim(),displayTitle);
	return EVAL_PAGE;
      } catch (IOException ex) {
	throw new JspException(ex.getMessage(), ex);
      }
    }


    //*********************************************************************
    // Public utility methods

    /**
     * Outputs <tt>text</tt> to <tt>pageContext</tt>'s current JspWriter.
     * If <tt>escapeXml</tt> is true, performs the following substring
     * replacements (to facilitate output to XML/HTML pages):
     *
     *    & -> &amp;
     *    < -> &lt;
     *    > -> &gt;
     *    " -> &#034;
     *    ' -> &#039;
     */
    public static void out(PageContext pageContext,
                           boolean escapeXml,
                           String textsub,String text,boolean displayTitle) throws IOException {
        JspWriter w = pageContext.getOut();
	if (!escapeXml){
		if(displayTitle&&(textsub.length()<text.length()+"...".length())){
			 w.write("<span title='");
             w.write(text);
             w.write("'>");
             w.write(textsub);
             w.write("</span>");
		}else{
			 w.write(textsub);
		}
	}else {
		if(displayTitle&&(textsub.length()<text.length()+"...".length())){
			w.write("<span title=\"");
			writeEscapedXml(text.toCharArray(), text.length(), w);
			w.write("\">");
			writeEscapedXml(textsub.toCharArray(), textsub.length(), w);
			w.write("</span>");
		}else{
			writeEscapedXml(textsub.toCharArray(), textsub.length(), w);
		}
       }
    }

    private static final int HIGHEST_SPECIAL = '>';
    private static char[][] specialCharactersRepresentation =
        new char[HIGHEST_SPECIAL + 1][];
    static {
        specialCharactersRepresentation['&'] = "&amp;".toCharArray();
        specialCharactersRepresentation['<'] = "&lt;".toCharArray();
        specialCharactersRepresentation['>'] = "&gt;".toCharArray();
        specialCharactersRepresentation['"'] = "&#034;".toCharArray();
        specialCharactersRepresentation['\''] = "&#039;".toCharArray();
    }

   /**
     *
     *  Optimized to create no extra objects and write directly
     *  to the JspWriter using blocks of escaped and unescaped characters
     *
     */
    private static void writeEscapedXml(char[] buffer, int length, JspWriter w)
                                        throws IOException {
        int start = 0;
        for (int i = 0; i < length; i++) {
            char c = buffer[i];
            if (c <= HIGHEST_SPECIAL) {                
                char[] escaped = specialCharactersRepresentation[c];
                if (escaped != null) {
                    // add unescaped portion
                    if (start < i) {
                        w.write(buffer,start,i-start);
                    }
                    // add escaped xml
                    w.write(escaped);
                    start = i + 1;
                }
            }
        }
        // add rest of unescaped portion
        if (start < length) {
            w.write(buffer,start,length-start);
        }
    }
    
	private String getResultbyLimitLength(String result, int maxlength) {
		if(maxlength>0){
			result = result.length()>maxlength?result.substring(0, maxlength)+"...":result.substring(0, result.length());
		}
		return result;
	}
    
    public void setValue(Object value) {
        this.value = value;
    }
      
    // for tag attribute
    public void setDefault(String def) {
        this.def = def;
    }
        
    // for tag attribute
    public void setEscapeXml(boolean escapeXml) {
        this.escapeXml = escapeXml;
    }
    //
    public void setMaxlength(int maxlength) {
        this.maxlength = maxlength;
    }

}
